package com.onlyxiahui.extend.boot.hibernate.config;

import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import javax.sql.DataSource;

import org.hibernate.SessionFactory;
import org.hibernate.boot.model.naming.PhysicalNamingStrategy;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;

import com.onlyxiahui.extend.query.hibernate.QueryContext;
import com.onlyxiahui.extend.query.hibernate.handler.xml.QueryItemException;

/**
 * 
 * Hibernate 相关配置 <br>
 * Date 2020-11-06 23:32:47<br>
 * 
 * @author XiaHui [onlovexiahui@qq.com]<br>
 * @since 1.0.0
 */
@Configuration
@ConditionalOnSingleCandidate(DataSource.class)
@AutoConfigureAfter({ DataSourceAutoConfiguration.class })
@EnableConfigurationProperties(AwareHibernateProperties.class)
public class AwareHibernateConfig {

	@Autowired
	private AwareHibernateProperties hibernateProperties;

	@Bean
	public QueryContext queryContext() {
		QueryContext bean = new QueryContext();

		String[] paths = hibernateProperties.getQueryPaths();
		if (null == paths || paths.length == 0) {
			String[] ls = { "classpath*:dao/query/*/*.*", "classpath*:dao/**/*.*" };
			paths = ls;
		}

		bean.setConfigLocations(paths);
		// bean.setConfigLocation("file:config/query/*.xml");
		try {
			bean.load();
		} catch (QueryItemException e) {
			e.printStackTrace();
		}
		return bean;
	}

	/**
	 * 持久层会话工厂类
	 *
	 * @return
	 */

	@Primary
	@Bean
	public FactoryBean<SessionFactory> sessionFactory(DataSource dataSource) {
		LocalSessionFactoryBean bean = new LocalSessionFactoryBean();
		bean.setDataSource(dataSource);

		String[] entityPackages = hibernateProperties.getEntityPackages();
		if (null != entityPackages && entityPackages.length > 0) {
			bean.setPackagesToScan(entityPackages);
		} else {
			bean.setPackagesToScan(new String[] {});
		}

		String name = hibernateProperties.getNamingStrategy();

		if (null != name && !name.isEmpty()) {

			try {
				Object o = Class.forName(name).newInstance();
				if (o instanceof PhysicalNamingStrategy) {
					bean.setPhysicalNamingStrategy((PhysicalNamingStrategy) o);
				}
			} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e1) {
				e1.printStackTrace();
			}
		}

		Properties properties = new Properties();

		Map<String, String> map = new HashMap<>(256);

		// map.put("dialect", "org.hibernate.dialect.MySQL8Dialect");
		map.put("show_sql", "false");
		map.put("hbm2ddl.auto", "none");
		map.put("query.substitutions", "true 1, false 0");
		map.put("jdbc.fetch_size", "50");
		map.put("jdbc.batch_size", "50");
		map.put("transaction.coordinator_class", "jdbc");
		map.put("allow_update_outside_transaction", "true");

		map.put("cache.use_query_cache", "true");
		map.put("cache.use_second_level_cache", "true");
		map.put("cache.region.factory_class", "org.hibernate.cache.jcache.JCacheRegionFactory");

		map.put("javax.cache.provider", "org.ehcache.jsr107.EhcacheCachingProvider");
		map.put("javax.cache.missing_cache_strategy", "create");

		if (null != hibernateProperties) {
			Map<String, String> setting = hibernateProperties.getSetting();
			map.putAll(setting);
		}

		for (Map.Entry<String, String> e : map.entrySet()) {
			properties.setProperty("hibernate." + e.getKey(), e.getValue());
		}
		bean.setHibernateProperties(properties);
		return bean;
	}
}
